package com.numbfish.ch41_ex03_oauth2_resource.config;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;

import java.util.List;

@Configuration
public class CustomResourceServerConfig {
    //@Value("${keySetURI}")
    private String keySetUri;
    // keySetURI=http://localhost:8081/oauth2/jwks
    // introspectionUri=http://127.0.0.1:8081/oauth2/introspect
    // resourceserver.clientID=resource_server
    // resourceserver.secret=resource_server_secret
    //@Value("${introspectionUri}")
    private String introspectionUri = "http://localhost:8081/oauth2/jwks";
    //@Value("${resourceserver.clientID}")
    private String resourceServerClientID = "resource_server";
    //@Value("${resourceserver.secret}")
    private String resourceServerSecret = "resource_server_secret";

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // http.oauth2ResourceServer(c -> {
        //     c       // Spring Security only supports JWTs or Opaque Tokens, not both at the same time.
        //             // .jwt(j -> j.jwkSetUri(keySetUri))
        //             .opaqueToken(o -> o.introspectionUri(introspectionUri).introspectionClientCredentials(resourceServerClientID, resourceServerSecret));
        // });
        // http.authorizeHttpRequests(c -> c.anyRequest().authenticated());
        http.oauth2ResourceServer(
                j -> j.authenticationManagerResolver(authenticationManagerResolver(
                        jwtDecoder(), opaqueTokenIntrospector()
                ))
        );
        http.cors(c -> {
            CorsConfigurationSource source = request -> {
                CorsConfiguration config = new CorsConfiguration();
                config.setAllowedOrigins(List.of("*"));
                config.setAllowedMethods(List.of("*"));
                config.setAllowedHeaders(List.of("*"));
                return config;
            };
            c.configurationSource(source);
        });

        http.csrf(csrf -> csrf.disable());
        return http.build();
    }

    @Bean
    public AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver(
            JwtDecoder jwtDecoder, OpaqueTokenIntrospector opaqueTokenIntrospector
    ) {
        AuthenticationManager jwtAuth = new ProviderManager(
                new JwtAuthenticationProvider(jwtDecoder)
        );

        AuthenticationManager opaqueAuth = new ProviderManager(
                new OpaqueTokenAuthenticationProvider(opaqueTokenIntrospector)
        );

        return (request) -> {
            if ("jwt".equals(request.getHeader("type"))) {
                return jwtAuth;
            } else {
                return opaqueAuth;
            }
        };
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder
                .withJwkSetUri("http://localhost:8081/oauth2/jwks")
                .build();
    }

    @Bean
    public OpaqueTokenIntrospector opaqueTokenIntrospector() {
        return new SpringOpaqueTokenIntrospector("http://127.0.0.1:8081/oauth2/introspect",
        //return new SpringOpaqueTokenIntrospector("http://localhost:8081/oauth2/introspect", 使用localhost会报错
                "resource_server", "resource_server_secret");
    }
}
